Libraries
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages -----------------------------------------------------------------------------------------------------------
filter(): dplyr, stats
lag(): dplyr, stats
library(lubridate)
Attaching package: 㤼㸱lubridate㤼㸲
The following object is masked from 㤼㸱package:base㤼㸲:
date
library(stringr)
library(e1071)
library(ReporteRs)
Loading required package: ReporteRsjars
library(slam)
library(tm)
Loading required package: NLP
Attaching package: 㤼㸱NLP㤼㸲
The following object is masked from 㤼㸱package:ggplot2㤼㸲:
annotate
library(topicmodels)
library(stm)
stm v1.2.2 (2017-03-28) successfully loaded. See ?stm for help.
Constants
theme_sparse <- theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black"), legend.key = element_blank())
Load models and data
# Data
load(file = "data/sparse_matrix_no_tex.zip")
sparse <- readCorpus(sparse, type = "slam")
# Metadata
load("data/posts_metadata.zip")
metadata$HW_Tag <- factor(metadata$HW_Tag, labels = c("No HW", "HW"))
# CTM
load("results/lda_final_40.zip")
load("results/ctm_final_110.zip")
load("results/stm_final_90.zip")
Least popular homework topics
metadata %>% filter(HW_Tag == "HW") %>% arrange(Score) %>% select(Id, Score, Title) %>% head()
Shared topic labels
# LDA: data = 10, model selection = 34
lda_gamma <- models40f@gamma %>% data.frame(i = 1:nrow(metadata))
lda_gamma <- data.frame(
lda_gamma %>% arrange(desc(X10)) %>% select(T10 = i) %>% head(5),
lda_gamma %>% arrange(desc(X34)) %>% select(T34 = i) %>% head(5)
)
print("LDA")
[1] "LDA"
print("Topic 10:")
[1] "Topic 10:"
apply(metadata[lda_gamma$T10, c("Id", "Title")], MARGIN = 1, FUN = paste, collapse = " ")
[1] "244815 Scaling large range values"
[2] "143414 Combining Standard Deviation (combined measurement uncertainty)"
[3] "175945 PCA on bimodal data: how to standardize the data?"
[4] "249959 Normalization of data with lots of zeros"
[5] "155407 How to compare 2 sets of p-values?"
print("Topic 34:")
[1] "Topic 34:"
apply(metadata[lda_gamma$T34, c("Id", "Title")], MARGIN = 1, FUN = paste, collapse = " ")
[1] "198365 Higher SIC and lower S.E. of residuals"
[2] "221016 AIC (QIC) - comparision of models?"
[3] "206808 Model comparison with chi-square difference test and BIC"
[4] " 94292 Comparing nested, non-linear models"
[5] " 83042 How can I evaluate my nonlinear model (without a model comparison)?"
# CTM: data = 20, model selection = 46
print("CTM")
[1] "CTM"
findThoughts(ctm_final_110, texts = trimws(paste(metadata$Id, metadata$Title)), topics = c(20, 46), n = 5)
Topic 20:
79511 How to combine two data sets (level-1 and level-2 data sets) for multilevel analysis in R
58333 What method can be used to test if three or more categorical sample data sets are from the same distribution?
123621 Can I use K-S test to distinguish distributions?
52010 Choosing a better data-set
209410 How can I create a synthetic data set resembling an existing data set?
Topic 46:
94292 Comparing nested, non-linear models
194601 Comparison between different models: hierarchical models and model with dummy
76893 Comparing linear models
174018 Extract goodness of fit from linear mixed effects models
215546 Using DIC for model selection: (in)valid comparisons
# STM: data = 20, model selection = 46
print("")
[1] ""
print("STM")
[1] "STM"
findThoughts(stm_final_90, texts = trimws(paste(metadata$Id, metadata$Title)), topics = c(20, 46), n = 5)
Topic 20:
104392 Multiple Imputation: Before or after case exclusion?
181399 How to combine multiply imputed datasets created with MICE from different cohorts?
104904 How to replace the missing data from AMELIA results
228463 perform quality check for imputed data with MICE in R
230369 imputation of missing values
Topic 46:
194601 Comparison between different models: hierarchical models and model with dummy
127353 What model should I use for this?
221016 AIC (QIC) - comparision of models?
76893 Comparing linear models
97901 R fit restricted AR(p) model
Topic proportions
# Label the top top_n topics
top_n <- 3
# LDA
lda_popular <- data.frame(
topic = 1:40,
theta_d = models40f@gamma[pop_idx, ]
)
lda_popular$top <- lda_popular$topic %in% (lda_popular %>% arrange(theta_d) %>% select(topic) %>% tail(top_n) %>% unlist())
lda_popular <- lda_popular %>% mutate(
terms = ifelse(!top,
"",
apply(topic %>% rbind(get_terms(models40f, k = 3)), MARGIN = 2, FUN = paste, collapse = "\n")
)
)
# CTM
ctm_popular <- data.frame(
topic = 1:110,
theta_d = ctm_final_110$theta[pop_idx, ]
)
ctm_popular$top <- ctm_popular$topic %in% (ctm_popular %>% arrange(theta_d) %>% select(topic) %>% tail(top_n) %>% unlist())
ctm_popular <- ctm_popular %>% mutate(
terms = ifelse(!top,
"",
apply(topic %>% cbind(sageLabels(ctm_final_110, n = 3)$marginal$frex), MARGIN = 1, FUN = paste, collapse = "\n")
)
)
# STM
stm_popular <- data.frame(
topic = 1:90,
theta_d = stm_final_90$theta[pop_idx, ]
)
stm_popular$top <- stm_popular$topic %in% (stm_popular %>% arrange(theta_d) %>% select(topic) %>% tail(top_n) %>% unlist())
stm_popular <- stm_popular %>% mutate(
terms = ifelse(!top,
"",
apply(topic %>% cbind(sageLabels(stm_final_90, n = 3)$marginal$frex), MARGIN = 1, FUN = paste, collapse = "\n")
)
)
# View top topics
lda_popular %>% filter(top) %>% arrange(desc(theta_d))
ctm_popular %>% filter(top) %>% arrange(desc(theta_d))
stm_popular %>% filter(top) %>% arrange(desc(theta_d))
# LDA results
lda1 <- lda_popular %>%
ggplot(aes(x = topic, y = theta_d)) +
geom_bar(stat = "identity", fill = "lightgray", width = .75) +
scale_y_continuous(expand = c(0, 0), labels = scales::percent, limits = c(0, .7), breaks = seq(0, 1, by = .1)) +
theme_sparse +
labs(x = "LDA topic number", y = "LDA topic proportions \\theta_d") +
geom_text(aes(label = terms, y = theta_d + .12), size = 3)
plot(lda1)

# CTM results
ctm1 <- ctm_popular %>%
ggplot(aes(x = topic, y = theta_d)) +
geom_bar(stat = "identity", fill = "lightgray", width = .75) +
scale_y_continuous(expand = c(0, 0), labels = scales::percent, limits = c(0, .6), breaks = seq(0, 1, by = .1)) +
theme_sparse +
labs(x = "CTM topic number", y = "CTM topic proportions \\theta_d") +
geom_text(aes(label = terms, y = theta_d + .1), size = 3)
plot(ctm1)

# STM results
stm1 <- stm_popular %>%
ggplot(aes(x = topic, y = theta_d)) +
geom_bar(stat = "identity", fill = "lightgray", width = .75) +
scale_y_continuous(expand = c(0, 0), labels = scales::percent, limits = c(0, .6), breaks = seq(0, 1, by = .1)) +
theme_sparse +
labs(x = "STM topic number", y = "STM topic proportions \\theta_d") +
geom_text(aes(label = terms, y = theta_d + .1), size = 3)
plot(stm1)

# Save results
mydoc <- docx()
mydoc <- addPlot(mydoc, function() print(lda1), width = 7, height = 2.5, vector.graphic = TRUE)
mydoc <- addPlot(mydoc, function() print(ctm1), width = 7, height = 2.5, vector.graphic = TRUE)
mydoc <- addPlot(mydoc, function() print(stm1), width = 7, height = 2.5, vector.graphic = TRUE)
writeDoc(mydoc, file = "results/fig/10-comparison-popular.docx")
Similar documents
# Hellinger distance function
hellinger <- function(target, doc_thetas) {
n <- nrow(doc_thetas)
target <- matrix(rep(target, each = n), nrow = n)
2 - 2 * rowSums(sqrt(target) * sqrt(doc_thetas))
}
LDA
lda_dist <- data.frame(
rown = 1:nrow(models40f@gamma),
hellinger = hellinger(models40f@gamma[pop_idx, ], models40f@gamma),
Id = metadata$Id,
Title = metadata$Title
) %>% arrange(hellinger)
{lda_dist %>% head()}[-1, ] %>% select(hellinger, Id, Title)
CTM
ctm_dist <- data.frame(
rown = 1:nrow(ctm_final_110$theta),
hellinger = hellinger(ctm_final_110$theta[pop_idx, ], ctm_final_110$theta),
Id = metadata$Id,
Title = metadata$Title
) %>% arrange (hellinger)
{ctm_dist %>% head()}[-1, ] %>% select(hellinger, Id, Title)
STM
stm_dist <- data.frame(
rown = 1:nrow(stm_final_90$theta),
hellinger = hellinger(stm_final_90$theta[pop_idx, ], stm_final_90$theta),
Id = metadata$Id,
Title = metadata$Title
) %>% arrange (hellinger)
{stm_dist %>% head()}[-1, ] %>% select(hellinger, Id, Title)
How long until one of the CTM/STM posts shows up in LDA?
LS0tDQp0aXRsZTogIk1vZGVsIGNvbXBhcmlzb25zIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBMaWJyYXJpZXMNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShlMTA3MSkNCmxpYnJhcnkoUmVwb3J0ZVJzKQ0KbGlicmFyeShzbGFtKQ0KbGlicmFyeSh0bSkNCmxpYnJhcnkodG9waWNtb2RlbHMpDQpsaWJyYXJ5KHN0bSkNCmBgYA0KDQojIENvbnN0YW50cw0KDQpgYGB7cn0NCnRoZW1lX3NwYXJzZSA8LSB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksIGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCkpDQpgYGANCiMgTG9hZCBtb2RlbHMgYW5kIGRhdGENCg0KYGBge3J9DQojIERhdGENCmxvYWQoZmlsZSA9ICJkYXRhL3NwYXJzZV9tYXRyaXhfbm9fdGV4LnppcCIpDQpzcGFyc2UgPC0gcmVhZENvcnB1cyhzcGFyc2UsIHR5cGUgPSAic2xhbSIpDQojIE1ldGFkYXRhDQpsb2FkKCJkYXRhL3Bvc3RzX21ldGFkYXRhLnppcCIpDQptZXRhZGF0YSRIV19UYWcgPC0gZmFjdG9yKG1ldGFkYXRhJEhXX1RhZywgbGFiZWxzID0gYygiTm8gSFciLCAiSFciKSkNCiMgQ1RNDQpsb2FkKCJyZXN1bHRzL2xkYV9maW5hbF80MC56aXAiKQ0KbG9hZCgicmVzdWx0cy9jdG1fZmluYWxfMTEwLnppcCIpDQpsb2FkKCJyZXN1bHRzL3N0bV9maW5hbF85MC56aXAiKQ0KYGBgDQoNCiMgTGVhc3QgcG9wdWxhciBob21ld29yayB0b3BpY3MNCg0KYGBge3J9DQptZXRhZGF0YSAlPiUgZmlsdGVyKEhXX1RhZyA9PSAiSFciKSAlPiUgYXJyYW5nZShTY29yZSkgJT4lIHNlbGVjdChJZCwgU2NvcmUsIFRpdGxlKSAlPiUgaGVhZCgpDQpgYGANCg0KIyBTaGFyZWQgdG9waWMgbGFiZWxzDQoNCmBgYHtyfQ0KIyBMREE6IGRhdGEgPSAxMCwgbW9kZWwgc2VsZWN0aW9uID0gMzQNCmxkYV9nYW1tYSA8LSBtb2RlbHM0MGZAZ2FtbWEgJT4lIGRhdGEuZnJhbWUoaSA9IDE6bnJvdyhtZXRhZGF0YSkpDQpsZGFfZ2FtbWEgPC0gZGF0YS5mcmFtZSgNCiAgbGRhX2dhbW1hICU+JSBhcnJhbmdlKGRlc2MoWDEwKSkgJT4lIHNlbGVjdChUMTAgPSBpKSAlPiUgaGVhZCg1KSwNCiAgbGRhX2dhbW1hICU+JSBhcnJhbmdlKGRlc2MoWDM0KSkgJT4lIHNlbGVjdChUMzQgPSBpKSAlPiUgaGVhZCg1KQ0KKQ0KcHJpbnQoIkxEQSIpDQpwcmludCgiVG9waWMgMTA6IikNCmFwcGx5KG1ldGFkYXRhW2xkYV9nYW1tYSRUMTAsIGMoIklkIiwgIlRpdGxlIildLCBNQVJHSU4gPSAxLCBGVU4gPSBwYXN0ZSwgY29sbGFwc2UgPSAiICIpDQpwcmludCgiVG9waWMgMzQ6IikNCmFwcGx5KG1ldGFkYXRhW2xkYV9nYW1tYSRUMzQsIGMoIklkIiwgIlRpdGxlIildLCBNQVJHSU4gPSAxLCBGVU4gPSBwYXN0ZSwgY29sbGFwc2UgPSAiICIpDQojIENUTTogZGF0YSA9IDIwLCBtb2RlbCBzZWxlY3Rpb24gPSA0Ng0KcHJpbnQoIkNUTSIpDQpmaW5kVGhvdWdodHMoY3RtX2ZpbmFsXzExMCwgdGV4dHMgPSB0cmltd3MocGFzdGUobWV0YWRhdGEkSWQsIG1ldGFkYXRhJFRpdGxlKSksIHRvcGljcyA9IGMoMjAsIDQ2KSwgbiA9IDUpDQojIFNUTTogZGF0YSA9IDIwLCBtb2RlbCBzZWxlY3Rpb24gPSA0Ng0KcHJpbnQoIiIpDQpwcmludCgiU1RNIikNCmZpbmRUaG91Z2h0cyhzdG1fZmluYWxfOTAsIHRleHRzID0gdHJpbXdzKHBhc3RlKG1ldGFkYXRhJElkLCBtZXRhZGF0YSRUaXRsZSkpLCB0b3BpY3MgPSBjKDIwLCA0NiksIG4gPSA1KQ0KYGBgDQoNCiMgTW9zdCB1cHZvdGVkIHBvc3QNCg0KYGBge3J9DQptZXRhZGF0YSAlPiUgYXJyYW5nZShkZXNjKFNjb3JlKSkgJT4lIHNlbGVjdChJZCwgU2NvcmUsIFZpZXdDb3VudCwgVGl0bGUpICU+JSBoZWFkKDEpDQojIFdoaWNoIHJvdyBpcyBpdCBpbj8NCnBvcF9pZHggPC0gd2hpY2gobWV0YWRhdGEkSWQgPT0gMjY5MSkNCmBgYA0KDQojIFRvcGljIHByb3BvcnRpb25zDQoNCmBgYHtyfQ0KIyBMYWJlbCB0aGUgdG9wIHRvcF9uIHRvcGljcw0KdG9wX24gPC0gMw0KDQojIExEQQ0KbGRhX3BvcHVsYXIgPC0gZGF0YS5mcmFtZSgNCiAgdG9waWMgPSAxOjQwLA0KICB0aGV0YV9kID0gbW9kZWxzNDBmQGdhbW1hW3BvcF9pZHgsIF0NCikNCmxkYV9wb3B1bGFyJHRvcCA8LSBsZGFfcG9wdWxhciR0b3BpYyAlaW4lIChsZGFfcG9wdWxhciAlPiUgYXJyYW5nZSh0aGV0YV9kKSAlPiUgc2VsZWN0KHRvcGljKSAlPiUgdGFpbCh0b3BfbikgJT4lIHVubGlzdCgpKQ0KbGRhX3BvcHVsYXIgPC0gbGRhX3BvcHVsYXIgJT4lIG11dGF0ZSgNCiAgdGVybXMgPSBpZmVsc2UoIXRvcCwNCiAgICAiIiwNCiAgICBhcHBseSh0b3BpYyAlPiUgcmJpbmQoZ2V0X3Rlcm1zKG1vZGVsczQwZiwgayA9IDMpKSwgTUFSR0lOID0gMiwgRlVOID0gcGFzdGUsIGNvbGxhcHNlID0gIlxuIikNCiAgKQ0KKQ0KDQojIENUTQ0KY3RtX3BvcHVsYXIgPC0gZGF0YS5mcmFtZSgNCiAgdG9waWMgPSAxOjExMCwNCiAgdGhldGFfZCA9IGN0bV9maW5hbF8xMTAkdGhldGFbcG9wX2lkeCwgXQ0KKQ0KY3RtX3BvcHVsYXIkdG9wIDwtIGN0bV9wb3B1bGFyJHRvcGljICVpbiUgKGN0bV9wb3B1bGFyICU+JSBhcnJhbmdlKHRoZXRhX2QpICU+JSBzZWxlY3QodG9waWMpICU+JSB0YWlsKHRvcF9uKSAlPiUgdW5saXN0KCkpDQpjdG1fcG9wdWxhciA8LSBjdG1fcG9wdWxhciAlPiUgbXV0YXRlKA0KICB0ZXJtcyA9IGlmZWxzZSghdG9wLA0KICAgICIiLA0KICAgIGFwcGx5KHRvcGljICU+JSBjYmluZChzYWdlTGFiZWxzKGN0bV9maW5hbF8xMTAsIG4gPSAzKSRtYXJnaW5hbCRmcmV4KSwgTUFSR0lOID0gMSwgRlVOID0gcGFzdGUsIGNvbGxhcHNlID0gIlxuIikNCiAgKQ0KKQ0KDQojIFNUTQ0Kc3RtX3BvcHVsYXIgPC0gZGF0YS5mcmFtZSgNCiAgdG9waWMgPSAxOjkwLA0KICB0aGV0YV9kID0gc3RtX2ZpbmFsXzkwJHRoZXRhW3BvcF9pZHgsIF0NCikNCnN0bV9wb3B1bGFyJHRvcCA8LSBzdG1fcG9wdWxhciR0b3BpYyAlaW4lIChzdG1fcG9wdWxhciAlPiUgYXJyYW5nZSh0aGV0YV9kKSAlPiUgc2VsZWN0KHRvcGljKSAlPiUgdGFpbCh0b3BfbikgJT4lIHVubGlzdCgpKQ0Kc3RtX3BvcHVsYXIgPC0gc3RtX3BvcHVsYXIgJT4lIG11dGF0ZSgNCiAgdGVybXMgPSBpZmVsc2UoIXRvcCwNCiAgICAiIiwNCiAgICBhcHBseSh0b3BpYyAlPiUgY2JpbmQoc2FnZUxhYmVscyhzdG1fZmluYWxfOTAsIG4gPSAzKSRtYXJnaW5hbCRmcmV4KSwgTUFSR0lOID0gMSwgRlVOID0gcGFzdGUsIGNvbGxhcHNlID0gIlxuIikNCiAgKQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KIyBWaWV3IHRvcCB0b3BpY3MNCmxkYV9wb3B1bGFyICU+JSBmaWx0ZXIodG9wKSAlPiUgYXJyYW5nZShkZXNjKHRoZXRhX2QpKQ0KY3RtX3BvcHVsYXIgJT4lIGZpbHRlcih0b3ApICU+JSBhcnJhbmdlKGRlc2ModGhldGFfZCkpDQpzdG1fcG9wdWxhciAlPiUgZmlsdGVyKHRvcCkgJT4lIGFycmFuZ2UoZGVzYyh0aGV0YV9kKSkNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDIuNX0NCiMgTERBIHJlc3VsdHMNCmxkYTEgPC0gbGRhX3BvcHVsYXIgJT4lDQogIGdncGxvdChhZXMoeCA9IHRvcGljLCB5ID0gdGhldGFfZCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAibGlnaHRncmF5Iiwgd2lkdGggPSAuNzUpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCwgbGltaXRzID0gYygwLCAuNyksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IC4xKSkgKw0KICB0aGVtZV9zcGFyc2UgKw0KICBsYWJzKHggPSAiTERBIHRvcGljIG51bWJlciIsIHkgPSAiTERBIHRvcGljIHByb3BvcnRpb25zIFxcdGhldGFfZCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRlcm1zLCB5ID0gdGhldGFfZCArIC4xMiksIHNpemUgPSAzKQ0KDQpwbG90KGxkYTEpDQoNCiMgQ1RNIHJlc3VsdHMNCmN0bTEgPC0gY3RtX3BvcHVsYXIgJT4lDQogIGdncGxvdChhZXMoeCA9IHRvcGljLCB5ID0gdGhldGFfZCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAibGlnaHRncmF5Iiwgd2lkdGggPSAuNzUpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCwgbGltaXRzID0gYygwLCAuNiksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IC4xKSkgKw0KICB0aGVtZV9zcGFyc2UgKw0KICBsYWJzKHggPSAiQ1RNIHRvcGljIG51bWJlciIsIHkgPSAiQ1RNIHRvcGljIHByb3BvcnRpb25zIFxcdGhldGFfZCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRlcm1zLCB5ID0gdGhldGFfZCArIC4xKSwgc2l6ZSA9IDMpDQoNCnBsb3QoY3RtMSkNCg0KIyBTVE0gcmVzdWx0cw0Kc3RtMSA8LSBzdG1fcG9wdWxhciAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gdG9waWMsIHkgPSB0aGV0YV9kKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJsaWdodGdyYXkiLCB3aWR0aCA9IC43NSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCBsaW1pdHMgPSBjKDAsIC42KSwgYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gLjEpKSArDQogIHRoZW1lX3NwYXJzZSArDQogIGxhYnMoeCA9ICJTVE0gdG9waWMgbnVtYmVyIiwgeSA9ICJTVE0gdG9waWMgcHJvcG9ydGlvbnMgXFx0aGV0YV9kIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdGVybXMsIHkgPSB0aGV0YV9kICsgLjEpLCBzaXplID0gMykNCg0KcGxvdChzdG0xKQ0KYGBgDQoNCmBgYHtyfQ0KIyBTYXZlIHJlc3VsdHMNCm15ZG9jIDwtIGRvY3goKQ0KbXlkb2MgPC0gYWRkUGxvdChteWRvYywgZnVuY3Rpb24oKSBwcmludChsZGExKSwgd2lkdGggPSA3LCBoZWlnaHQgPSAyLjUsIHZlY3Rvci5ncmFwaGljID0gVFJVRSkNCm15ZG9jIDwtIGFkZFBsb3QobXlkb2MsIGZ1bmN0aW9uKCkgcHJpbnQoY3RtMSksIHdpZHRoID0gNywgaGVpZ2h0ID0gMi41LCB2ZWN0b3IuZ3JhcGhpYyA9IFRSVUUpDQpteWRvYyA8LSBhZGRQbG90KG15ZG9jLCBmdW5jdGlvbigpIHByaW50KHN0bTEpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDIuNSwgdmVjdG9yLmdyYXBoaWMgPSBUUlVFKQ0Kd3JpdGVEb2MobXlkb2MsIGZpbGUgPSAicmVzdWx0cy9maWcvMTAtY29tcGFyaXNvbi1wb3B1bGFyLmRvY3giKQ0KYGBgDQoNCiMgU2ltaWxhciBkb2N1bWVudHMNCg0KYGBge3J9DQojIEhlbGxpbmdlciBkaXN0YW5jZSBmdW5jdGlvbg0KaGVsbGluZ2VyIDwtIGZ1bmN0aW9uKHRhcmdldCwgZG9jX3RoZXRhcykgew0KICBuIDwtIG5yb3coZG9jX3RoZXRhcykNCiAgdGFyZ2V0IDwtIG1hdHJpeChyZXAodGFyZ2V0LCBlYWNoID0gbiksIG5yb3cgPSBuKQ0KICAyIC0gMiAqIHJvd1N1bXMoc3FydCh0YXJnZXQpICogc3FydChkb2NfdGhldGFzKSkNCn0NCmBgYA0KDQojIyBMREENCg0KYGBge3J9DQpsZGFfZGlzdCA8LSBkYXRhLmZyYW1lKA0KICByb3duID0gMTpucm93KG1vZGVsczQwZkBnYW1tYSksDQogIGhlbGxpbmdlciA9IGhlbGxpbmdlcihtb2RlbHM0MGZAZ2FtbWFbcG9wX2lkeCwgXSwgbW9kZWxzNDBmQGdhbW1hKSwNCiAgSWQgPSBtZXRhZGF0YSRJZCwNCiAgVGl0bGUgPSBtZXRhZGF0YSRUaXRsZQ0KKSAlPiUgYXJyYW5nZShoZWxsaW5nZXIpDQoNCntsZGFfZGlzdCAlPiUgaGVhZCgpfVstMSwgXSAgJT4lIHNlbGVjdChoZWxsaW5nZXIsIElkLCBUaXRsZSkNCmBgYA0KDQojIyBDVE0NCg0KYGBge3J9DQpjdG1fZGlzdCA8LSBkYXRhLmZyYW1lKA0KICByb3duID0gMTpucm93KGN0bV9maW5hbF8xMTAkdGhldGEpLA0KICBoZWxsaW5nZXIgPSBoZWxsaW5nZXIoY3RtX2ZpbmFsXzExMCR0aGV0YVtwb3BfaWR4LCBdLCBjdG1fZmluYWxfMTEwJHRoZXRhKSwNCiAgSWQgPSBtZXRhZGF0YSRJZCwNCiAgVGl0bGUgPSBtZXRhZGF0YSRUaXRsZQ0KKSAlPiUgYXJyYW5nZSAoaGVsbGluZ2VyKQ0KDQp7Y3RtX2Rpc3QgJT4lIGhlYWQoKX1bLTEsIF0gICU+JSBzZWxlY3QoaGVsbGluZ2VyLCBJZCwgVGl0bGUpDQpgYGANCg0KIyMgU1RNDQoNCmBgYHtyfQ0Kc3RtX2Rpc3QgPC0gZGF0YS5mcmFtZSgNCiAgcm93biA9IDE6bnJvdyhzdG1fZmluYWxfOTAkdGhldGEpLA0KICBoZWxsaW5nZXIgPSBoZWxsaW5nZXIoc3RtX2ZpbmFsXzkwJHRoZXRhW3BvcF9pZHgsIF0sIHN0bV9maW5hbF85MCR0aGV0YSksDQogIElkID0gbWV0YWRhdGEkSWQsDQogIFRpdGxlID0gbWV0YWRhdGEkVGl0bGUNCikgJT4lIGFycmFuZ2UgKGhlbGxpbmdlcikNCg0Ke3N0bV9kaXN0ICU+JSBoZWFkKCl9Wy0xLCBdICAlPiUgc2VsZWN0KGhlbGxpbmdlciwgSWQsIFRpdGxlKQ0KYGBgDQoNCiMjIEhvdyBsb25nIHVudGlsIG9uZSBvZiB0aGUgQ1RNL1NUTSBwb3N0cyBzaG93cyB1cCBpbiBMREE/DQoNCmBgYHtyLCByb3dzLnByaW50ID0gMjB9DQp7bGRhX2Rpc3QgJT4lIHNlbGVjdChoZWxsaW5nZXIsIElkLCBUaXRsZSl9WzI6MjAsIF0NCmBgYA==